#pragma once
#include <string>
#include <spdlog/spdlog.h>
#include <SQLiteCpp/SQLiteCpp.h>

#include "kungfu/wingchun/msg.h"

namespace kungfu
{
	namespace wingchun
	{
		namespace mapper
		{
			const int LOCATION_INFO_LEN = 128;

			struct Location
			{
				uint32_t uid;
				char info[LOCATION_INFO_LEN];

				std::string get_info() const
				{
					return std::string(info);
				}

				void set_info(const std::string& info)
				{
					strncpy(this->info, info.c_str(), LOCATION_INFO_LEN);
				}
#ifndef _WIN32
			} __attribute__((packed));
#else
			};
#endif

			class LocationMapper
			{
			public:
				LocationMapper(const std::string& file_name) : db_(file_name.c_str(), SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE) {
					create_table_if_not_exist();
				};

				std::vector<Location> get_location_info(const std::uint32_t uid)
				{
					std::vector<Location> assets;
					SQLite::Statement query(db_, "select * from location where uid = ?");

					try
					{
						query.bind(1, uid);
						if (query.executeStep())
						{
							Location result = {};

							result.uid = query.getColumn(0).getInt();
							result.set_info(query.getColumn(1).getString());

							assets.push_back(result);
						}
					}
					catch (std::exception& e)
					{
						SPDLOG_ERROR("exception: {}", e.what());
					}
					return assets;
				};

				void add_location(const location_ptr& location)
				{
					SQLite::Statement insert(db_, "INSERT INTO location VALUES(?, ?)");
					try
					{
						nlohmann::json msg_json;
						msg_json["uid"] = location->uid;
						msg_json["uname"] = location->uname;
						msg_json["mode"] = get_mode_name(location.get()->mode);
						msg_json["category"] = get_category_name(location.get()->category);
						msg_json["group"] = location->group;
						msg_json["name"] = location->name;

						insert.bind(1, (long long)(location->uid));
						insert.bind(2, msg_json.dump());
						insert.exec();
					}
					catch (std::exception& e)
					{
						SPDLOG_ERROR("exception: {}", e.what());
					}
				}

				void create_table_if_not_exist()
				{
					std::string sql = "CREATE TABLE IF NOT EXISTS location(  \n"
						"					uid INTEGER PRIMARY KEY NOT NULL,\n"
						"                   info				CHAR(128));";
					try
					{
						db_.exec(sql);
					}
					catch (std::exception& e)
					{
						SPDLOG_ERROR("failed to create table, sql: {}, exception: {}", sql.c_str(), e.what());
					}
				}
			private:
				SQLite::Database db_;
			};
		}
	}
}